/**
 * 字符串链式操作类
 * 
 * 提供丰富的字符串操作方法，所有方法均支持链式调用，使字符串处理更加简洁优雅。
 * 该类与strings模块中的helpers函数集成，复用了现有的字符串处理逻辑，确保功能一致性和代码复用性。
 * 
 * 主要功能包括：
 * - 基础操作：连接、设置、获取值
 * - 格式化操作：大小写转换、首字母大写、标题化
 * - 填充操作：左右填充、修剪
 * - 内容操作：替换、截取、分割、反转
 * - 查询方法：包含、开头、结尾检查、长度获取
 * - 高级功能：HTML转义/解码、空白字符处理、截断等
 * 
 * @example
 * // 基本用法
 * const result = new StringChain('hello')
 *   .concat(' world')
 *   .toUpperCase()
 *   .replace('WORLD', 'TUI')
 *   .valueOf(); // 返回 'HELLO TUI'
 * 
 * // 使用便捷函数
 * import { chain } from 'tui/strings';
 * const result2 = chain('  user@example.com  ')
 *   .trim()
 *   .splitAt('@', 0)
 *   .valueOf(); // 返回 'user'
 */
// 移除了从helpers导入的函数，这些函数现在在类内部实现

export class StringChain {
  /**
   * 私有字符串值
   * @private
   */
  private __value: string;

  /**
   * 创建StringChain实例
   * @param {string} value - 初始字符串值，默认为空字符串
   * @example
   * // 创建一个空字符串链
   * const emptyChain = new StringChain();
   * // 创建一个带初始值的字符串链
   * const helloChain = new StringChain('hello');
   */
  constructor(value: string = '') {
    this.__value = value;
  }

  /**
   * 获取当前字符串值（原始值转换）
   * 
   * 当对象需要被转换为原始值时自动调用，例如在数学运算、比较操作或使用原始值的场景中。
   * 对于StringChain类，返回内部存储的字符串原始值。
   * 
   * @returns {string} 当前的字符串原始值
   * @example
   * const chain = new StringChain('test');
   * chain.valueOf(); // 返回 'test'
   * // 在需要原始值的场景中自动调用
   * const length = chain.length; // 内部调用valueOf()后获取length
   */
  valueOf(): string {
    return this.__value;
  }

  /**
   * 转换为字符串表示
   * 
   * 当对象需要被转换为字符串时自动调用，例如在字符串拼接、String()构造函数或模板字符串中。
   * 对于StringChain类，返回内部存储的字符串的字符串表示。
   * 
   * @returns {string} 当前字符串的字符串表示
   * @example
   * const chain = new StringChain('test');
   * chain.toString(); // 返回 'test'
   * String(chain); // 自动调用toString()，返回 'test'
   * 'Value: ' + chain; // 自动调用toString()，返回 'Value: test'
   */
  toString(): string {
    return this.__value;
  }

  /**
   * 设置新的字符串值
   * @param {string} value - 新的字符串值
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('old').set('new').valueOf(); // 返回 'new'
   */
  set(value: string): this {
    this.__value = value;
    return this;
  }

  /**
   * 连接字符串
   * @param {string} str - 要连接的字符串
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').concat(' world').valueOf(); // 返回 'hello world'
   */
  concat(str: string): this {
    this.__value += str;
    return this;
  }

  /**
   * 在左侧填充字符
   * @param {number} length - 目标长度
   * @param {string} [char=' '] - 填充字符，默认为空格
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('abc').padLeft(5).valueOf(); // 返回 '  abc'
   * new StringChain('123').padLeft(5, '0').valueOf(); // 返回 '00123'
   */
  padLeft(length: number, char: string = ' '): this {
    if (this.__value.length >= length) return this;

    // 处理空填充字符串的情况
    const padString = char || ' ';
    const padLength = length - this.__value.length;

    // 计算需要重复填充字符串的次数
    const repeatTimes = Math.ceil(padLength / padString.length);
    const fullPad = padString.repeat(repeatTimes);
    const padding = fullPad.substring(0, padLength);

    this.__value = padding + this.__value;
    return this;
  }

  /**
   * 在右侧填充字符
   * @param {number} length - 目标长度
   * @param {string} [char=' '] - 填充字符，默认为空格
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('abc').padRight(5).valueOf(); // 返回 'abc  '
   * new StringChain('123').padRight(5, '0').valueOf(); // 返回 '12300'
   */
  padRight(length: number, char: string = ' '): this {
    if (this.__value.length >= length) return this;

    // 处理空填充字符串的情况
    const padString = char || ' ';
    const padLength = length - this.__value.length;

    // 计算需要重复填充字符串的次数
    const repeatTimes = Math.ceil(padLength / padString.length);
    const fullPad = padString.repeat(repeatTimes);
    const padding = fullPad.substring(0, padLength);

    this.__value = this.__value + padding;
    return this;
  }

  /**
   * 修剪左侧空白字符
   * @param {string} [chars=''] - 要从左侧清除的字符或字符串，默认为空字符串（表示清除空白符）
   * @param {number} [limit=0] - 清除限制数量：0表示清除全部，正数表示限制清除的数量
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('  hello').ltrim().valueOf(); // 返回 'hello'
   * new StringChain('aaaaworld').ltrim('a').valueOf(); // 返回 'world'
   */
  ltrim(chars: string = '', limit: number = 0): this {
    if (typeof chars !== 'string') {
        throw new Error('ltrim function expects string arguments');
    }

    // 验证limit参数
    if (typeof limit !== 'number' || limit < 0 || !Number.isInteger(limit)) {
        throw new Error('ltrim function expects a non-negative integer for limit parameter');
    }

    let startIndex = 0;
    let count = 0;
    const hasLimit = limit > 0;

    // 如果chars为空字符串，表示清除空白符
    if (chars === '') {
        // 循环检查并跳过空白符
        while (startIndex < this.__value.length && /\s/.test(this.__value[startIndex])) {
            // 如果有清除限制，且已经达到限制数量，则停止
            if (hasLimit && count >= limit) {
                break;
            }

            startIndex++;
            count++;
        }
    } else {
        // 循环检查并清除开头所有匹配的字符串（不单独处理单字符）
        while (startIndex < this.__value.length) {
            // 检查当前位置是否匹配整个chars字符串
            if (this.__value.slice(startIndex, startIndex + chars.length) === chars) {
                // 如果有清除限制，且已经达到限制数量，则停止
                if (hasLimit && count >= limit) {
                    break;
                }

                startIndex += chars.length;
                count++;
            } else {
                // 遇到不匹配的字符串，停止清除
                break;
            }
        }
    }

    this.__value = this.__value.slice(startIndex);
    return this;
  }

  /**
   * 修剪右侧空白字符
   * @param {string} [chars=''] - 要从右侧清除的字符或字符串，默认为空字符串（表示清除空白符）
   * @param {number} [limit=0] - 清除限制数量：0表示清除全部，正数表示限制清除的数量
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello  ').rtrim().valueOf(); // 返回 'hello'
   * new StringChain('helloooo').rtrim('o').valueOf(); // 返回 'hello'
   */
  rtrim(chars: string = '', limit: number = 0): this {
    // 注意：当显式传入undefined时，需要特别处理，不能依赖默认参数
    // 因为在测试中显式传入undefined as any，需要确保抛出错误
    if (typeof chars !== 'string') {
        throw new Error('rtrim function expects string arguments');
    }

    // 验证limit参数
    if (typeof limit !== 'number' || limit < 0 || !Number.isInteger(limit)) {
        throw new Error('rtrim function expects a non-negative integer for limit parameter');
    }

    let endIndex = this.__value.length;
    let count = 0;
    const hasLimit = limit > 0;

    // 如果chars为空字符串，表示清除空白符
    if (chars === '') {
        // 循环检查并跳过空白符
        while (endIndex > 0 && /\s/.test(this.__value[endIndex - 1])) {
            // 如果有清除限制，且已经达到限制数量，则停止
            if (hasLimit && count >= limit) {
                break;
            }

            endIndex--;
            count++;
        }
    } else {
        // 循环检查并清除结尾所有匹配的字符串（不单独处理单字符）
        while (endIndex > 0) {
            // 检查当前位置是否匹配整个chars字符串
            if (endIndex >= chars.length && this.__value.slice(endIndex - chars.length, endIndex) === chars) {
                // 如果有清除限制，且已经达到限制数量，则停止
                if (hasLimit && count >= limit) {
                    break;
                }

                endIndex -= chars.length;
                count++;
            } else {
                // 遇到不匹配的字符串，停止清除
                break;
            }
        }
    }

    this.__value = this.__value.slice(0, endIndex);
    return this;
  }

  /**
   * 修剪两侧空白字符
   * @param {string} [chars=''] - 要从两侧清除的字符或字符串，默认为空字符串（表示清除空白符）
   * @param {number} [limit=0] - 清除限制数量：0表示清除全部，正数表示限制清除的数量
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('  hello  ').trim().valueOf(); // 返回 'hello'
   * new StringChain('aaaaworldaaaa').trim('a').valueOf(); // 返回 'world'
   */
  trim(chars: string = '', limit: number = 0): this {
    // 先从左侧清除，再从右侧清除
    return this.ltrim(chars, limit).rtrim(chars, limit);
  }

  /**
   * 转换为小写
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('HELLO').toLowerCase().valueOf(); // 返回 'hello'
   */
  toLowerCase(): this {
    this.__value = this.__value.toLowerCase();
    return this;
  }

  /**
   * 转换为大写
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').toUpperCase().valueOf(); // 返回 'HELLO'
   */
  toUpperCase(): this {
    this.__value = this.__value.toUpperCase();
    return this;
  }

  /**
   * 首字母大写
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').toUpperCaseFirst().valueOf(); // 返回 'Hello'
   */
  toUpperCaseFirst(): this {
    if (!this.__value) return this;

    this.__value = this.__value.charAt(0).toUpperCase() + this.__value.slice(1);
    return this;
  }

  /**
   * 转换为小写首字母
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('HELLO').toLowerCaseFirst().valueOf(); // 返回 'hELLO'
   */
  toLowerCaseFirst(): this {
    if (!this.__value) return this;

    this.__value = this.__value.charAt(0).toLowerCase() + this.__value.slice(1);
    return this;
  }

  /**
   * 每个单词首字母大写
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello world').titleCase().valueOf(); // 返回 'Hello World'
   */
  toTitleCase(): this {
    this.__value = this.__value.replace(/\b\w/g, char => char.toUpperCase());
    return this;
  }

  /**
   * 替换匹配项
   * @param {string|RegExp} searchValue - 要查找的字符串或正则表达式
   * @param {string} replaceValue - 替换值
   * @param {number} count - 替换次数，默认0表示替换全部
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').replace('h', 'H').valueOf(); // 返回 'Hello'
   * new StringChain('hello hello').replace('hello', 'hi', 1).valueOf(); // 返回 'hi hello'
   */
  replace(searchValue: string | RegExp, replaceValue: string, count: number = 0): this {
    // 如果count为0或负数，替换全部
    if (count <= 0) {
      if (typeof searchValue === 'string') {
        // 对于字符串搜索，转换为全局正则表达式以替换所有匹配项
        const regex = new RegExp(searchValue.replace(/[.*+?^${}()|\[\]\\]/g, '\\$&'), 'g');
        this.__value = this.__value.replace(regex, replaceValue);
      } else {
        // 对于正则表达式，确保它是全局的
        const regex = searchValue.global ? searchValue : new RegExp(searchValue.source, searchValue.flags + 'g');
        this.__value = this.__value.replace(regex, replaceValue);
      }
      return this;
    }

    // 处理替换指定次数的情况
    let replaceCount = 0;

    if (typeof searchValue === 'string') {
      // 对于字符串搜索，使用正则表达式实现替换次数控制
      const regex = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
      this.__value = this.__value.replace(regex, (match) => {
        if (replaceCount < count) {
          replaceCount++;
          return replaceValue;
        }
        return match;
      });
    } else {
      // 对于正则表达式搜索，使用函数控制替换次数
      this.__value = this.__value.replace(searchValue, (match) => {
        if (replaceCount < count) {
          replaceCount++;
          return replaceValue;
        }
        return match;
      });
    }

    return this;
  }

  /**
   * 截取字符串
   * @param {number} start - 开始索引
   * @param {number} [end] - 结束索引（可选）
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello world').slice(6).valueOf(); // 返回 'world'
   * new StringChain('hello world').slice(0, 3).valueOf(); // 返回 'hel'
   */
  slice(start: number, end?: number): this {
    this.__value = this.__value.slice(start, end);
    return this;
  }

  /**
   * 截取指定长度的字符串
   * @param {number} start - 开始索引
   * @param {number} [length] - 要截取的长度
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').sub(1, 3).valueOf(); // 返回 'ell'
   */
  sub(start: number, length?: number): this {
    this.__value = length !== undefined ? this.__value.slice(start, start + length) : this.__value.slice(start);
    return this;
  }

  /**
   * 分割字符串并取指定索引的部分
   * @param {string} separator - 分隔符
   * @param {number} index - 要获取的索引
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('a,b,c').splitAt(1, ',').valueOf(); // 返回 'b'
   */
  splitAt(index: number, separator: string = ','): this {
    const parts = this.__value.split(separator);
    if (index >= 0 && index < parts.length) {
      this.__value = parts[index];
    }
    return this;
  }

  /**
   * 限制字符串长度，如果超过则添加省略号
   * @param {number} maxLength - 最大长度
   * @param {string} [suffix='...'] - 省略后缀，默认为'...'
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello world').truncate(5).valueOf(); // 返回 'he...'
   */
  truncate(maxLength: number, suffix: string = '...'): this {
    if (this.__value.length <= maxLength) return this;

    const truncateLength = maxLength - suffix.length;
    if (truncateLength <= 0) {
      this.__value = suffix.slice(0, maxLength);
    } else {
      this.__value = this.__value.slice(0, truncateLength) + suffix;
    }
    return this;
  }

  /**
   * 检查字符串是否包含指定的子字符串
   * @param {string} searchString - 要搜索的子字符串
   * @returns {boolean} 是否包含
   * @example
   * new StringChain('hello').isIncludes('ell'); // 返回 true
   */
  isIncludes(searchString: string): boolean {
    return this.__value.includes(searchString);
  }

  /**
   * 检查字符串是否以指定的子字符串开头
   * @param {string} searchString - 要搜索的子字符串
   * @returns {boolean} 是否以指定子字符串开头
   * @example
   * new StringChain('hello').isStartsWith('he'); // 返回 true
   */
  isStartsWith(searchString: string): boolean {
    return this.__value.startsWith(searchString);
  }

  /**
   * 检查字符串是否以指定的子字符串结尾
   * @param {string} searchString - 要搜索的子字符串
   * @returns {boolean} 是否以指定子字符串结尾
   * @example
   * new StringChain('hello').isEndsWith('lo'); // 返回 true
   */
  isEndsWith(searchString: string): boolean {
    return this.__value.endsWith(searchString);
  }

  /**
   * 获取字符串长度
   * @returns {number} 字符串长度
   * @example
   * new StringChain('hello').length(); // 返回 5
   */
  length(): number {
    return this.__value.length;
  }

  /**
   * 反转字符串
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('hello').reverse().valueOf(); // 返回 'olleh'
   */
  reverse(): this {
    this.__value = this.__value.split('').reverse().join('');
    return this;
  }

  /**
   * 去除字符串中的所有空白字符
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('h e l l o').removeWhitespace().valueOf(); // 返回 'hello'
   */
  removeWhitespace(): this {
    this.__value = this.__value.replace(/\s+/g, '');
    return this;
  }

  /**
   * 将字符串中的所有空白字符替换为指定字符
   * @param {string} [char=' '] - 替换字符，默认为单个空格
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('h  e\tl\no').normalizeWhitespace().valueOf(); // 返回 'h e l o'
   */
  replaceWhitespace(char: string = ' '): this {
    this.__value = this.__value.replace(/\s+/g, char);
    return this;
  }

  /**
   * 转义HTML特殊字符
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('<div>').escapeHtml().valueOf(); // 返回 '&lt;div&gt;'
   */
  escapeHtml(): this {
    const entities: Record<string, string> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#39;',
      '`': '&#96;',
      '\\': '&#92;',
      '/': '&#47;',
    };

    this.__value = this.__value.replace(/[&<>"']/g, char => entities[char] || char);
    return this;
  }

  /**
   * 从HTML实体解码
   * @returns {StringChain} 当前实例，支持链式调用
   * @example
   * new StringChain('&lt;div&gt;').unescapeHtml().valueOf(); // 返回 '<div>'
   */
  unescapeHtml(): this {
    const entities: Record<string, string> = {
      '&amp;': '&',
      '&lt;': '<',
      '&gt;': '>',
      '&quot;': '"',
      '&#39;': "'"
    };

    this.__value = this.__value.replace(/&amp;|&lt;|&gt;|&quot;|&#39;/g, entity => entities[entity] || entity);
    return this;
  }
}